﻿#include "QuestProgressInfo.h"

using namespace Server::MirObjects;
using namespace Server::MirEnvir;

namespace Server::MirDatabase
{

    Server::MirEnvir::Envir *QuestProgressInfo::getEnvir()
    {
        return Envir::getMain();
    }

    bool QuestProgressInfo::getTaken() const
    {
        return StartDateTime > DateTime::MinValue;
    }

    bool QuestProgressInfo::getCompleted() const
    {
        return EndDateTime < DateTime::MaxValue;
    }

    bool QuestProgressInfo::getNew() const
    {
        return StartDateTime > DateTime::Now.AddDays(-1);
    }

    QuestProgressInfo::QuestProgressInfo(int index)
    {
        Index = index;

        Info = getEnvir()->QuestInfoList.FirstOrDefault([&] (std::any e)
        {
            return e->Index == index;
        });

        for (auto kill : *Info->KillTasks)
        {
            KillTaskCount.push_back(0);
        }

        for (auto item : *Info->ItemTasks)
        {
            ItemTaskCount.push_back(0);
        }

        for (auto flag : *Info->FlagTasks)
        {
            FlagTaskSet.push_back(false);
        }

        CheckCompleted();
    }

    QuestProgressInfo::QuestProgressInfo(BinaryReader *reader)
    {
        Index = reader->ReadInt32();
        Info = getEnvir()->QuestInfoList.FirstOrDefault([&] (std::any e)
        {
            return e->Index == Index;
        });

        StartDateTime = DateTime::FromBinary(reader->ReadInt64());
        EndDateTime = DateTime::FromBinary(reader->ReadInt64());

        int count = reader->ReadInt32();
        for (int i = 0; i < count; i++)
        {
            KillTaskCount.push_back(reader->ReadInt32());
        }

        count = reader->ReadInt32();
        for (int i = 0; i < count; i++)
        {
            ItemTaskCount.push_back(reader->ReadInt64());
        }

        count = reader->ReadInt32();
        for (int i = 0; i < count; i++)
        {
            FlagTaskSet.push_back(reader->ReadBoolean());
        }
    }

    void QuestProgressInfo::Save(BinaryWriter *writer)
    {
        writer->Write(Index);

        writer->Write(StartDateTime.ToBinary());
        writer->Write(EndDateTime.ToBinary());

        writer->Write(KillTaskCount.size());
        for (int i = 0; i < KillTaskCount.size(); i++)
        {
            writer->Write(KillTaskCount[i]);
        }

        writer->Write(ItemTaskCount.size());
        for (int i = 0; i < ItemTaskCount.size(); i++)
        {
            writer->Write(ItemTaskCount[i]);
        }

        writer->Write(FlagTaskSet.size());
        for (int i = 0; i < FlagTaskSet.size(); i++)
        {
            writer->Write(FlagTaskSet[i]);
        }
    }

    void QuestProgressInfo::ResyncTasks()
    {
        if (Info->KillTasks.size() != KillTaskCount.size())
        {
            if (KillTaskCount.size() > Info->KillTasks.size())
            {
                KillTaskCount.RemoveRange(Info->KillTasks.size(), KillTaskCount.size() - Info->KillTasks.size());
            }
            else
            {
                while (KillTaskCount.size() < Info->KillTasks.size())
                {
                    KillTaskCount.push_back(0);
                }
            }

            EndDateTime = DateTime::MaxValue;
        }

        if (Info->ItemTasks.size() != ItemTaskCount.size())
        {
            if (ItemTaskCount.size() > Info->ItemTasks.size())
            {
                ItemTaskCount.RemoveRange(Info->ItemTasks.size(), ItemTaskCount.size() - Info->ItemTasks.size());
            }
            else
            {
                while (ItemTaskCount.size() < Info->ItemTasks.size())
                {
                    ItemTaskCount.push_back(0);
                }
            }

            EndDateTime = DateTime::MaxValue;
        }

        if (Info->FlagTasks.size() != FlagTaskSet.size())
        {
            if (FlagTaskSet.size() > Info->FlagTasks.size())
            {
                FlagTaskSet.RemoveRange(Info->FlagTasks.size(), FlagTaskSet.size() - Info->FlagTasks.size());
            }
            else
            {
                while (FlagTaskSet.size() < Info->FlagTasks.size())
                {
                    FlagTaskSet.push_back(false);
                }
            }

            EndDateTime = DateTime::MaxValue;
        }

    }

    bool QuestProgressInfo::CheckCompleted()
    {
        UpdateTasks();

        bool canComplete = true;

        for (int i = 0; i < Info->KillTasks.size(); i++)
        {
            if (KillTaskCount[i] >= Info->KillTasks[i]->Count)
            {
                continue;
            }

            canComplete = false;
        }

        for (int i = 0; i < Info->ItemTasks.size(); i++)
        {
            if (ItemTaskCount[i] >= Info->ItemTasks[i]->Count)
            {
                continue;
            }

            canComplete = false;
        }

        for (int i = 0; i < Info->FlagTasks.size(); i++)
        {
            if (FlagTaskSet[i])
            {
                continue;
            }

            canComplete = false;
        }

        if (!canComplete)
        {
            return false;
        }

        if (!getCompleted())
        {
            EndDateTime = DateTime::Now;
        }

        return true;
    }

    bool QuestProgressInfo::NeedItem(ItemInfo *iInfo)
    {
        return Info->ItemTasks.Where([&] (task, i)
        {
            return ItemTaskCount[i] < task->Count && task->Item == iInfo;
        }).Any();
    }

    bool QuestProgressInfo::NeedKill(MonsterInfo *mInfo)
    {
        //if (info.Name != name && !info.Name.Replace(" ", "").StartsWith(name, StringComparison.OrdinalIgnoreCase)) continue;
        return Info->KillTasks.Where([&] (task, i)
        {
            return KillTaskCount[i] < task->Count && mInfo->Name.StartsWith(task::Monster->Name, StringComparison::OrdinalIgnoreCase);
        }).Any();
    }

    bool QuestProgressInfo::NeedFlag(int flagNumber)
    {
        return Info->FlagTasks.Where([&] (task, i)
        {
            return FlagTaskSet[i] == false && task->Number == flagNumber;
        }).Any();
    }

    void QuestProgressInfo::ProcessKill(MonsterInfo *mInfo)
    {
        if (Info->KillTasks.size() < 1)
        {
            return;
        }

        for (int i = 0; i < Info->KillTasks.size(); i++)
        {
            //if (Info.KillTasks[i].Monster.Index != mobIndex) continue;
            if (!mInfo->Name.StartsWith(Info->KillTasks[i]->Monster->Name, StringComparison::OrdinalIgnoreCase))
            {
                continue;
            }
            KillTaskCount[i]++;

            return;
        }
    }

    void QuestProgressInfo::ProcessItem(std::vector<UserItem*> &inventory)
    {
        for (int i = 0; i < Info->ItemTasks.size(); i++)
        {
            long long count = inventory.Where([&] (std::any item)
            {
                return item != nullptr;
            }).Where([&] (std::any item)
            {
                return item->Info == Info->ItemTasks[i]->Item;
            }).Aggregate<UserItem*, long long>(0, [&] (current, item)
            {
                return current + item->Count;
            });

            ItemTaskCount[i] = count;
        }
    }

    void QuestProgressInfo::ProcessFlag(std::vector<bool> &Flags)
    {
        for (int i = 0; i < Info->FlagTasks.size(); i++)
        {
            for (int j = 0; j < Flags.size() - 1000; j++)
            {
                if (Info->FlagTasks[i]->Number != j || !Flags[j])
                {
                    continue;
                }

                FlagTaskSet[i] = Flags[j];
                break;
            }
        }
    }

    void QuestProgressInfo::UpdateTasks()
    {
        TaskList = std::vector<std::string>();

        UpdateKillTasks();
        UpdateItemTasks();
        UpdateFlagTasks();
        UpdateGotoTask();
    }

    void QuestProgressInfo::UpdateKillTasks()
    {
        if (Info->KillMessage.length() > 0 && Info->KillTasks.size() > 0)
        {
            bool allComplete = true;
            for (int i = 0; i < Info->KillTasks.size(); i++)
            {
                if (KillTaskCount[i] >= Info->KillTasks[i]->Count)
                {
                    continue;
                }

                allComplete = false;
            }

            TaskList.push_back(StringHelper::formatSimple("{0} {1}", Info->KillMessage, allComplete ? "(Completed)" : ""));
            return;
        }

        for (int i = 0; i < Info->KillTasks.size(); i++)
        {
            if ((Info->KillTasks[i]->Message).empty())
            {
                TaskList.push_back(std::string::Format("Kill {0}: {1}/{2} {3}", Info->KillTasks[i]->Monster.getGameName(), KillTaskCount[i], Info->KillTasks[i]->Count, KillTaskCount[i] >= Info->KillTasks[i]->Count ? "(Completed)" : ""));
            }
            else
            {
                TaskList.push_back(StringHelper::formatSimple("{0} {1}", Info->KillTasks[i]->Message, KillTaskCount[i] >= Info->KillTasks[i]->Count ? "(Completed)" : ""));
            }

        }
    }

    void QuestProgressInfo::UpdateItemTasks()
    {
        if (Info->ItemMessage.length() > 0 && Info->ItemTasks.size() > 0)
        {
            bool allComplete = true;
            for (int i = 0; i < Info->ItemTasks.size(); i++)
            {
                if (ItemTaskCount[i] >= Info->ItemTasks[i]->Count)
                {
                    continue;
                }

                allComplete = false;
            }

            TaskList.push_back(StringHelper::formatSimple("{0} {1}", Info->ItemMessage, allComplete ? "(Completed)" : ""));
            return;
        }

        for (int i = 0; i < Info->ItemTasks.size(); i++)
        {
            if ((Info->ItemTasks[i]->Message).empty())
            {
                TaskList.push_back(std::string::Format("Collect {0}: {1}/{2} {3}", Info->ItemTasks[i]->Item->getFriendlyName(), ItemTaskCount[i], Info->ItemTasks[i]->Count, ItemTaskCount[i] >= Info->ItemTasks[i]->Count ? "(Completed)" : ""));
            }
            else
            {
                TaskList.push_back(StringHelper::formatSimple("{0} {1}", Info->ItemTasks[i]->Message, ItemTaskCount[i] >= Info->ItemTasks[i]->Count ? "(Completed)" : ""));
            }
        }
    }

    void QuestProgressInfo::UpdateFlagTasks()
    {
        if (Info->FlagMessage.length() > 0)
        {
            bool allComplete = true;
            for (int i = 0; i < Info->FlagTasks.size(); i++)
            {
                if (FlagTaskSet[i])
                {
                    continue;
                }

                allComplete = false;
            }

            TaskList.push_back(StringHelper::formatSimple("{0} {1}", Info->FlagMessage, allComplete ? "(Completed)" : ""));
            return;
        }

        for (int i = 0; i < Info->FlagTasks.size(); i++)
        {
            if ((Info->FlagTasks[i]->Message).empty())
            {
                TaskList.push_back(StringHelper::formatSimple("Activate Flag {0} {1}", Info->FlagTasks[i]->Number, FlagTaskSet[i] ? "(Completed)" : ""));
            }
            else
            {
                TaskList.push_back(StringHelper::formatSimple("{0} {1}", Info->FlagTasks[i]->Message, FlagTaskSet[i] ? "(Completed)" : ""));
            }

        }
    }

    void QuestProgressInfo::UpdateGotoTask()
    {
        if (Info->GotoMessage.length() <= 0 || !getCompleted())
        {
            return;
        }

        TaskList.push_back(Info->GotoMessage);
    }

    ClientQuestProgress *QuestProgressInfo::CreateClientQuestProgress()
    {
        ClientQuestProgress *tempVar = new ClientQuestProgress();
        tempVar->Id = Index;
        tempVar->TaskList = TaskList;
        tempVar->Taken = getTaken();
        tempVar->Completed = getCompleted();
        tempVar->New = getNew();

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was used in a 'return' or 'throw' statement.
        return tempVar;
    }
}
